/**
 *  @file
 *  @brief   实体单元本构矩阵解析
 *  @author  王欢
 *  @date    2024.10.16
 *  @version v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */
#include "SolidMaterialParser.h"

#include <cassert>

#include "Utility/Logging/SGLogger.h"

#include "DataStructure/Input/Material/MaterialTypes.h"
#include "DataStructure/Input/Solver/TenserTranform.h"

#include "DBManager/IService/Input/Material/IAnisotropic3DMaterialService.h"
#include "DBManager/IService/Input/Material/IIsotropicMaterialService.h"
#include "DBManager/IService/Input/Material/IMaterialSummaryService.h"

#include "SGFem/Pre/Assembly/CoordinateProcessor.h"

using SG::Algebra::Matrixd;
using SG::DataStructure::Common::Real;
using SG::DataStructure::Common::Status;
using SG::DataStructure::FEM::Anisotropic3DMaterial;
using SG::DataStructure::FEM::IsotropicMaterial;
using SG::DataStructure::FEM::MaterialTypes;
using SG::DataStructure::FEM::TenserTranform;
using namespace SG::DBManager;
using SG::FEMSolver::CoordinateProcessor;
using SG::FEMSolver::Element::SolidMaterialParser;

void SolidMaterialParser::ComputeMaterialCoordTrans
(
const SG::DataStructure::Common::Id mCId,
const SG::Algebra::Matrixd&         T,
const SG::Algebra::Matrixd&         TS,
_OUT SG::Algebra::Matrixd&          TMat
)
{
    if (0 == mCId)
    {
        TMat = T.Transpose ();
    }
    else if (mCId > 0)
    {
        const auto& coordProcessor = CoordinateProcessor::GetInstance ();
        const auto coordP = coordProcessor.GetCoord (mCId);
        coordProcessor.GetCoordTrans (mCId, coordP->GetOrigin (), _OUT TMat);
        TMat = TMat * T.Transpose ();
    }
    else if (-2 == mCId)
    {
        TMat = TS * T.Transpose ();
    }
    else if (-1 == mCId)
    {
        // ToDo：CTETRA、CPENTA 单元的 Nastran 单元坐标系
        TMat = SG::Algebra::identity (3);
    }
    else
    {
        SGError << "The CORDM of PSOLID should not be less than -2!";
    }
}

void SolidMaterialParser::ComputeElasticMatrix
(
const SG::DBManager::DBServiceFactorySP dbServiceFactory,
const SG::DataStructure::Common::Id     mId,
const SG::Algebra::Matrixd&             TMat,
_OUT SG::Algebra::Matrixd&              D,
_OUT SG::DataStructure::Common::Real&   rho
)
{
    // 获取材料类型
    auto matTypes = dbServiceFactory->get<IMaterialSummaryService> ()->GetMaterialType (mId);

    for (auto&& matType : matTypes)
    {
        switch (matType)
        {
        // 各项同性材料
        case MaterialTypes::MATTYPE_Isotropic:
        {
            IsotropicMaterial material;
            if (Status::STATUS_Failure == dbServiceFactory->get<IIsotropicMaterialService> ()->FindById (mId, _OUT material))
            {
                assert (0);
            }
            const Real& Young_E = material.m_E;
            const Real& mu      = material.m_nu;
            const Real& G       = material.m_G;
            // 计算 lambda（拉梅第一参数）
            const Real lame = Young_E * mu / (1.0 + mu) / (1.0 - 2.0 * mu);

            D (0, 0) = lame + G * 2.0;
            D (0, 1) = lame;
            D (0, 2) = lame;
            D (1, 0) = lame;
            D (1, 1) = lame + G * 2.0;
            D (1, 2) = lame;
            D (2, 0) = lame;
            D (2, 1) = lame;
            D (2, 2) = lame + G * 2.0;
            D (3, 3) = G;
            D (4, 4) = G;
            D (5, 5) = G;

            rho = material.m_rho;
            return;
        }
        case MaterialTypes::MATTYPE_3DAnisotropic:
        {
            Anisotropic3DMaterial mat9;
            if (Status::STATUS_Failure == dbServiceFactory->get<IAnisotropic3DMaterialService> ()->FindById (mId, _OUT mat9))
            {
                assert (0);
            }
            D = mat9.GetD ();
            Matrixd TStrain (6, 6);
            TenserTranform::StrainTrans (TMat, _OUT TStrain);
            D = TStrain.Transpose () * D * TStrain;
            rho = mat9.m_rho;
            return;
        }

        default:
            break;
        }
    }
}